/* QtLua -- Lua bindings for Qt
   Copyright (C) 2011, Jarek Pelczar

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 3 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General
   Public License along with this library; if not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301 USA

*/

#ifndef QLUASCRIPTVALUE_H
#define QLUASCRIPTVALUE_H

#include <QExplicitlySharedDataPointer>
#include <QString>
#include <QVariant>
#include <QHash>
#include <QList>

class QLuaScriptValueData;
class QLuaScriptEngine;

class QLuaScriptValue;

typedef QList<QLuaScriptValue> QLuaScriptValueList;

class QLuaScriptValue
{
public:
    enum StringWrapMode
    {
        WrapCopy,
        WrapPersistentData
    };

    enum SpecialValue {
        NoneValue,
        NilValue
    };

    QLuaScriptValue();
    QLuaScriptValue(const QLuaScriptValue &);
    QLuaScriptValue &operator=(const QLuaScriptValue &);
    ~QLuaScriptValue();

    explicit QLuaScriptValue(bool value);
    explicit QLuaScriptValue(int value);
    explicit QLuaScriptValue(qreal value);
    explicit QLuaScriptValue(const QString& value);
    explicit QLuaScriptValue(const QLatin1String& value);
    explicit QLuaScriptValue(const char * value);
    explicit QLuaScriptValue(const QByteArray& value);
    explicit QLuaScriptValue(SpecialValue value);
    QLuaScriptValue(const char * value, int length, StringWrapMode wrapMode = WrapCopy);

    QLuaScriptEngine * engine() const;
    QVariant toVariant() const;

    bool isValid() const;
    bool isNil() const;
    bool isBool () const;
    bool isFunction() const;
    bool isNumber() const;
    bool isString() const;
    bool isTable() const;
    bool isUserData() const;
    bool isLightUserData() const;
    bool isThread() const;
    bool isMetaObject() const;
    bool isQObject() const;
    bool isObject() const;

    QLuaScriptValue call(const QLuaScriptValueList& args);

    static QLuaScriptValue newFromStack(QLuaScriptEngine * engine, int index);

    QLuaScriptValue property(int index) const;
    QLuaScriptValue property(const QByteArray& key) const;
    QLuaScriptValue property(const char * key) const;
    QLuaScriptValue rawProperty(int index) const;
    QLuaScriptValue rawProperty(const QByteArray& key) const;
    QLuaScriptValue rawProperty(const char * key) const;
    bool setProperty(int index, const QLuaScriptValue& value);
    bool setProperty(const QByteArray& key, const QLuaScriptValue& value);
    bool setProperty(const char * key, const QLuaScriptValue& value);
    bool setRawProperty(int index, const QLuaScriptValue& value);
    bool setRawProperty(const QByteArray& key, const QLuaScriptValue& value);
    bool setRawProperty(const char * key, const QLuaScriptValue& value);

    QVariantMap toMap() const;
    QVariantHash toHash() const;
    QVariantList toList() const;
    QStringList toStringList() const;
    QString toUnicode() const;
    bool toBool() const;
    qreal toNumber() const;
    int toInteger() const;
    QByteArray toString() const;
    void * toLightUserData() const;
    void * toUserData() const;
    const QMetaObject * toMetaObject() const;
    QObject * toQObject() const;

    bool strictlyEquals(const QLuaScriptValue& other) const;
    bool equals(const QLuaScriptValue& other) const;
    bool lessThan(const QLuaScriptValue& other) const;

    int nativeType() const;

    bool operator < (const QLuaScriptValue& other) const;
    bool operator == (const QLuaScriptValue& other) const;
    bool operator != (const QLuaScriptValue& other) const;

    uint hashCode() const;

    QLuaScriptValue metaTable() const;
    void setMetaTable(const QLuaScriptValue& value);

    void pushToStack(QLuaScriptEngine * engine = 0) const;

    friend QDebug operator << (QDebug d, const QLuaScriptValue& value);

    void * lua_cast_helper(int type_id) const;

    template<typename T> T * cast_to() const
    {
        return (T *)lua_cast_helper(qMetaTypeId<T>());
    }

private:
    friend class QLuaScriptValueData;
    QExplicitlySharedDataPointer<QLuaScriptValueData> data;
};

static inline uint qHash(const QLuaScriptValue &key) {
    return key.hashCode();
}

QDebug operator << (QDebug d, const QLuaScriptValue& value);

template<typename T> inline T * qtlua_scriptvalue_cast(const QLuaScriptValue& value)
{
    return (T *)value.lua_cast_helper(qMetaTypeId<T>());
}

template<typename T> inline T qobject_cast(const QLuaScriptValue& value)
{
    QObject * o = value.toQObject();
    if(!o) return NULL;
    return qobject_cast<T>(o);
}

Q_DECLARE_METATYPE(QLuaScriptValue)

#endif // QLUASCRIPTVALUE_H
